package com.lmk.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.lmk.basic.exception.BusinessException;
import com.lmk.basic.jwt.JwtUtils;
import com.lmk.basic.jwt.LoginData;
import com.lmk.basic.jwt.RsaUtils;
import com.lmk.basic.service.Impl.BaseServiceImpl;
import com.lmk.basic.util.AjaxResult;
import com.lmk.basic.util.HttpUtil;
import com.lmk.basic.util.Md5Utils;
import com.lmk.basic.util.StrUtils;
import com.lmk.system.domain.Menu;
import com.lmk.system.mapper.MenuMapper;
import com.lmk.system.mapper.PermissionMapper;
import com.lmk.user.constant.WxConstants;
import com.lmk.user.domain.Logininfo;
import com.lmk.user.domain.User;
import com.lmk.user.domain.Wxuser;
import com.lmk.user.dto.LoginDto;
import com.lmk.user.mapper.LogininfoMapper;
import com.lmk.user.mapper.UserMapper;
import com.lmk.user.mapper.WxuserMapper;
import com.lmk.user.service.ILogininfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 业务实现类：
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {
    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    @Transactional
    public Map<String, Object> accountLogin(LoginDto loginDto) {

        String account = loginDto.getAccount();
        String checkPass = loginDto.getCheckPass();
        // 空值校验
        if(StringUtils.isEmpty(account.trim()) || StringUtils.isEmpty(checkPass.trim())){
            throw new BusinessException("账号或密码为空");
        }
        // 判断账号是否存在
        Logininfo logininfo = logininfoMapper.loadByAccount(loginDto);
        if(logininfo==null){
            throw new BusinessException("账户不存在");
        }else {
            String checkPass2 = loginDto.getCheckPass();
            // 密码加密加盐，并获取加密加盐的密码
            String p1 = Md5Utils.encrypByMd5(checkPass2 + logininfo.getSalt());
            String p2 = logininfo.getPassword();
            if (!p1.equals(p2)) {
                throw new BusinessException("密码错误！");
            }else{
               /* // 成功，生成token
                String token = UUID.randomUUID().toString();
                redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
                //4.将token和对存在Map ，然后返回
                HashMap<String, Object> map = new HashMap<>();
                map.put("token",token);
                logininfo.setSalt(null);
                logininfo.setPassword(null);
                map.put("logininfo",logininfo);*/
                Map<String,Object> map = loginSuccessJwtHandler(logininfo);
                return map;
            }
        }
    }


    // 微信登录
    @Override
    public AjaxResult wechatLogin(String code) {
        // 准备请求和替换参数
        String url = WxConstants.GET_ACK_URL.replace("APPID", WxConstants.APPID)//源码时代提供
                .replace("SECRET", WxConstants.SECRET)//源码时代提供
                .replace("CODE", code);//手机扫描后传过来的code
        //发送请求-返回json格式参数
        String jsonStr = HttpUtil.httpGet(url);
        // 把json格式转化为一个json对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        // 获取token
        String accessToken = jsonObject.getString("access_token");
        // 获取openId
        String openId = jsonObject.getString("openid");
        // 根据opdnid查询t_wxuser对象
        Wxuser wxuser = wxuserMapper.loadByOpenId(openId);
        // 1.如果有，就返回前端，直接登录
        if(wxuser!=null && wxuser.getUserId()!=null && userMapper.loadById(wxuser.getUserId())!=null){
            User user = userMapper.loadById(wxuser.getUserId());
            Logininfo logininfo = logininfoMapper.loadById(user.getLogininfoId());

            /*String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
            //4.将token和对存在Map ，然后返回
            HashMap<String, Object> map = new HashMap<>();
            map.put("token",token);
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo",logininfo);*/

            Map<String,Object> map = loginSuccessJwtHandler(logininfo);
            return AjaxResult.me().setResultObj(map);
        }else {
            // 2.如果没有就要进行验证
            String param = "?accessToken="+accessToken+"&openId="+openId;
            return AjaxResult.me().setSuccess(false).setResultObj(param);
        }
    }

    private Map<String, Object> loginSuccessJwtHandler(Logininfo logininfo) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("logininfo",logininfo);
        // 封装一个logindata对象
        LoginData loginData = new LoginData();
        loginData.setLogininfo(logininfo);
        if (logininfo.getType()==0){// 如果是管理员
            // 1.获取当前登陆人logininfo.getId(),并获取菜单，若是后台管理员，获取菜单
            List<Menu> menus = menuMapper.getMenuByLogininfoId(logininfo.getId());
            // 2.若是后台管理员，获取菜单权限
            List<String> permissions = permissionMapper.loadPerssionSnByLogininfoId(logininfo.getId());
            loginData.setPermissions(permissions);
            loginData.setMenus(menus);
            // 所有菜单，返回给前端，动态路由，实现动态菜单
            map.put("menus",menus);
            // 所有权限，返回给前端，资源权限
            map.put("permissions",permissions);
        }
        try {
            // 3.获取私钥
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("auth_rsa.pri").getFile());
            // 4.通过私钥对logindata对象进行加密，加密成jwt字符串
            String jwtToken = JwtUtils.generateTokenExpireInMinutes(loginData, privateKey, 30);
            // 5.将以上四个信息，logindata。所有菜单，所有权限，jwttoken都要封装到map进行返回，最终返回给前端。
            // loginfo 返回给前端，回显信息
            map.put("logininfo",logininfo);
            // jwttoken 返回给前端，登录权限
            map.put("token",jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    // 微信绑定
    @Override
    public AjaxResult binderWechat(Map<String, String> map) {

        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");

        //1.空值校验
        if (StringUtils.isEmpty(phone.trim()) || StringUtils.isEmpty(verifyCode.trim())) {
            throw new BusinessException("信息不能有空格");
        }
        //2.手机验证码是否过期，是否正确
        Object obj = redisTemplate.opsForValue().get("binder:" + phone);
        if(obj==null){
            throw new BusinessException("验证码已过期!!!,请重新获取");
        }
        //3.判断是否正确
        if(!obj.toString().split(":")[0].equals(verifyCode)){
            throw new BusinessException("验证码错误");
        }
        //4.替换参数
        String url = WxConstants.GET_USER_URL.replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String jsonStr = HttpUtil.httpGet(url);
        //5.把json字符串转为json对象 获取wxUser对象
        Wxuser wxuser = jsonStr2Wxuser(jsonStr);
        //6.将wxUser对象与User对象进行绑定
        User user = userMapper.loadByPhone(phone);
        if(user==null){//根据电话没有找到user对象
            //通过phone创建user对象
            user = phone2User(phone);
            Logininfo logininfo = user2Logininfo(user);

            logininfoMapper.save(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.save(user);
        }
        // 将user保存到wxuser
        wxuser.setUserId(user.getId());
        wxuserMapper.save(wxuser);

        //微信免密登入 返回 token，logininfo对象
        Logininfo logininfo = logininfoMapper.loadById(user.getLogininfoId());
        Map<String,Object> mapTmp  = loginSuccessJwtHandler(logininfo);
        mapTmp.put("wxuser",wxuser);
        return AjaxResult.me().setResultObj(mapTmp);
       /* String token = UUID.randomUUID().toString();
        //去掉密码和盐值 - 安全
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        Map<String, Object> map1 = new HashMap<>();
        map1.put("token",token);
        map1.put("logininfo",logininfo);

        return AjaxResult.me().setResultObj(map1);*/

    }


    // 将json字符串转化为wxuser对象
    private Wxuser jsonStr2Wxuser(String jsonStr) {
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(jsonObject.getString("openid"));
        wxuser.setNickname(jsonObject.getString("nickname"));
        wxuser.setSex(jsonObject.getInteger("sex"));
        wxuser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxuser.setUnionid(jsonObject.getString("unionid"));
        //获取地址
        String country = jsonObject.getString("country");
        String province = jsonObject.getString("province");
        String city = jsonObject.getString("city");
        wxuser.setAddress(country+province+city);
        return wxuser;
    }
    private User phone2User(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        //盐值
        String salt = StrUtils.getComplexRandomString(32);
        String randomPwd = StrUtils.getComplexRandomString(6);
        String md5Pwd = Md5Utils.encrypByMd5(randomPwd+salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        user.setState(1);
        return user;
    }
    // 将user信息保存到Logininfo
    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);
        return logininfo;
    }



}
